package com.biodiv.miracle.aop.proxy;

import com.biodiv.miracle.aop.aspect.AspectObject;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: tianquan
 * @date: 2024-10-08  14:33
 * @Description: 切面代理工厂
 */
public class ProxyRegistration {
    /**
     * 需要走代理的注解映射，键为注解类，值为对应的AopEntity对象
     */
    final Map<Class<? extends Annotation>, AspectObject> aopAnnotationMap = new HashMap<>();

    /**
     * 需要走代理的方法映射，键为方法名，值为对应的AopEntity对象
     */
    final Map<String, AspectObject> aopMethodsNameMap = new HashMap<>();

    /**
     * 需要走代理的类映射，键为类，值为对应的AopEntity对象
     */
    final Map<Class<?>, AspectObject> aopClassMap = new HashMap<>();

    /**
     * 向aopAnnotationMap中添加需要走代理的注解
     *
     * @param annotation 需要代理的注解类
     * @param aspectObject  包含代理信息的实体对象
     */
    public void putAopAnnotationName(Class<? extends Annotation> annotation, AspectObject aspectObject) {
        aopAnnotationMap.put(annotation, aspectObject);
    }

    /**
     * 向aopMethodsNameMap中添加需要走代理的方法名
     *
     * @param method    需要代理的方法名
     * @param aspectObject 包含代理信息的实体对象
     */
    public void putAopMethodsName(String method, AspectObject aspectObject) {
        aopMethodsNameMap.put(method, aspectObject);
    }

    /**
     * 向aopClassMap中添加需要走代理的类
     *
     * @param className 需要代理的类
     * @param aspectObject 包含代理信息的实体对象
     */
    public void putAopClass(Class<?> className, AspectObject aspectObject) {
        aopClassMap.put(className, aspectObject);
    }

    /**
     * 判断是否有必要的创建对象的代理类
     *
     * @param bean 需要判断是否创建代理类的Bean对象
     * @return 如果需要创建代理类，则返回代理对象；否则返回原对象
     */
    public Object isNecessaryCreateProxy(Object bean) {
        Class<?> aClass = bean.getClass();
        // 当前bean的所有方法
        List<String> currentBeanAllMethods = Arrays.stream(bean.getClass().getDeclaredMethods())
                .map(Method::getName)
                .collect(Collectors.toList());

        // 整个类的方法是否都要增强
        AspectObject aspectObject = aopClassMap.get(aClass);
        if (aspectObject != null) {
            return PoxyFactory.getProxy(bean, currentBeanAllMethods,
                    aspectObject.getBeforeMethod(), aspectObject.getAroundMethod(), aspectObject.getAfterMethod(), aspectObject.getObject()
            );
        }

        // 某些方法需要生成代理
        List<String> proxyMethods = aopMethodsNameMap.keySet().stream()
                .filter(methodName -> currentBeanAllMethods.stream().anyMatch(poxyMethodName -> poxyMethodName.equals(methodName)))
                .collect(Collectors.toList());

        if (!proxyMethods.isEmpty()) {
            aspectObject = aopMethodsNameMap.get(proxyMethods.get(0));
        }

        // 注解
        for (Method method : aClass.getDeclaredMethods()) {
            for (Annotation annotation : method.getAnnotations()) {
                aspectObject = aopAnnotationMap.get(annotation.annotationType());
                if (aspectObject == null) {
                    continue;
                }
                proxyMethods.add(method.getName());
                break;
            }
        }

        if (!proxyMethods.isEmpty()) {
            return PoxyFactory.getProxy(bean, proxyMethods,
                    aspectObject.getBeforeMethod(), aspectObject.getAroundMethod(), aspectObject.getAfterMethod(), aspectObject.getObject()
            );
        }

        // 不需要走代理
        return bean;
    }

}
